package ltd.ninefish.framework.core.utils;

import cn.hutool.core.date.DateTime;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import ltd.ninefish.framework.core.constant.NfConst;
import ltd.ninefish.framework.core.constant.SecurityConst;
import ltd.ninefish.framework.core.constant.TokenConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhaoxiubin
 * create-time 2024-01-16 12:31
 * description Jwt工具类
 **/

public class JwtUtil {

    private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);

    /**
     * json web token 过期时间（单位：分钟）；0为永不过期
     */
    private static int expire = 0;

    /**
     * json web token 密钥
     */
    public static String secret = TokenConst.SECRET;

    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    public static String createToken(Map<String, String> claims)
    {
        //构建头部信息
        Map<String,Object> header = new HashMap<>();
        header.put(TokenConst.JWT_HEADER_TYPE,  TokenConst.JWT_TYPE_JWT);
        header.put(TokenConst.JWT_HEADER_ALGORITHM, "HS512");
        //根据私钥构建密钥信息
        //HmacSHA256（HS256）、HmacSHA384（HS384）、HmacSHA512（HS512）
        //SHA256withECDSA（ES256）、SHA256withRSA（RS256）、SHA512withRSA（RS512）
        Algorithm algorithm = Algorithm.HMAC512(secret);
        JWTCreator.Builder builder = JWT.create();
        builder = builder.withHeader(header)
                //声明,签名是有谁生成 例如 服务器
                .withIssuer(NfConst.COMPANY_NAME_EN);
        for(Map.Entry< String, String> map: claims.entrySet()){
            builder = builder.withClaim(map.getKey(), map.getValue());
        }
        // 判断是否为永不过期
        if (expire != 0){
            LocalDateTime date = LocalDateTime.now().plusMinutes(expire);
            builder.withExpiresAt(new DateTime(date));
        }
        return builder.sign(algorithm);
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    public static Map<String, Claim>  parseToken(String token)
    {
        Map<String, Claim> claims = new HashMap<>(1);
        try {
            // 根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC512(secret);
            JWTVerifier verifier = JWT.require(algorithm).build();
            // 效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            claims = jwt.getClaims();
        }
        //SignatureVerificationException:                签名不一致异常
        //TokenExpiredException:                         令牌过期异常
        //AlgorithmMismatchException:                    算法不匹配异常
        //InvalidClaimException:                         失效的payload异常
        catch (TokenExpiredException e){
            log.error(e.getMessage(), e);
        }
        catch (JWTVerificationException e) {
            log.error(e.getMessage(), e);
        }
        return claims;
    }

    /**
     * 根据令牌获取用户标识
     *
     * @param token 令牌
     * @return 用户ID
     */
    public static String getUserKey(String token)
    {
        Map<String, Claim> claims = parseToken(token);
        return getValue(claims, SecurityConst.USER_KEY);
    }

    /**
     * 根据令牌获取用户标识
     *
     * @param claims 身份信息
     * @return 用户ID
     */
    public static String getUserKey(Map<String, Claim> claims)
    {
        return getValue(claims, SecurityConst.USER_KEY);
    }

    /**
     * 根据令牌获取用户ID
     *
     * @param token 令牌
     * @return 用户ID
     */
    public static String getUserId(String token)
    {
        Map<String, Claim> claims = parseToken(token);
        return getValue(claims, SecurityConst.DETAILS_USER_ID);
    }

    /**
     * 根据身份信息获取用户ID
     *
     * @param claims 身份信息
     * @return 用户ID
     */
    public static String getUserId(Map<String, Claim> claims)
    {
        return getValue(claims, SecurityConst.DETAILS_USER_ID);
    }

    /**
     * 根据令牌获取用户名
     *
     * @param token 令牌
     * @return 用户名
     */
    public static String getUserName(String token)
    {
        Map<String, Claim> claims = parseToken(token);
        return getValue(claims, SecurityConst.DETAILS_USERNAME);
    }

    /**
     * 根据身份信息获取用户名
     *
     * @param claims 身份信息
     * @return 用户名
     */
    public static String getUserName(Map<String, Claim> claims)
    {
        return getValue(claims, SecurityConst.DETAILS_USERNAME);
    }

    /**
     * 根据身份信息获取键值
     *
     * @param claims 身份信息
     * @param key 键
     * @return 值
     */
    public static String getValue(Map<String, Claim> claims, String key)
    {
        String result = "";
        if (claims.containsKey(key)){
            result = claims.get(key).asString();
        }
        return result;
    }
}
